手势输入来源
Scripting 提供了与 SwiftUI 类似的完整手势系统,可为任意视图(如 <VStack>、<HStack>、<Text> 等)添加点击、长按、拖动、缩放、旋转等交互行为。
开发者既可以使用简化的 onTapGesture / onLongPressGesture / onDragGesture 等直接属性,也可以使用新的 Gesture 类接口和 gesture 修饰符,以获得更灵活的组合方式。
自定义键盘专用触摸区还可使用 iOS 18+ 的 onTouchGesture,接收 UIKit 的逐指开始、移动、结束和取消事件。它是独立接口,不接受 GestureMask,也不改变已有 DragGesture;速度/预测、取消及多指迁移规则请先阅读其文档。
一、直接手势属性(简化用法)
这些属性提供最直接的交互绑定方式,适合快速使用场景。
1. onTapGesture
在识别到点击手势时执行指定操作。
类型
onTapGesture?: (() => void) | {
count: number
perform: () => void
}
参数
示例
// 单击触发
<VStack onTapGesture={() => console.log('点击了')} />
// 双击触发
<HStack
onTapGesture={{
count: 2,
perform: () => console.log('双击了')
}}
/>
2. onLongPressGesture
在识别到长按手势时执行操作,可监听按压状态。
类型
onLongPressGesture?: (() => void) | {
minDuration?: number
maxDuration?: number
perform: () => void
onPressingChanged?: (state: boolean) => void
}
参数
示例
// 基本用法
<VStack onLongPressGesture={() => console.log('长按触发')} />
// 自定义参数
<HStack
onLongPressGesture={{
minDuration: 800,
maxDuration: 3000,
perform: () => console.log('长按成功'),
onPressingChanged: isPressing =>
console.log(isPressing ? '正在按压' : '已松开')
}}
/>
3. onDragGesture
为视图添加拖动交互,支持实时位置变化与拖动结束事件。
类型
onDragGesture?: {
minDistance?: number
coordinateSpace?: 'local' | 'global'
onChanged?: (details: DragGestureDetails) => void
onEnded?: (details: DragGestureDetails) => void
}
参数
DragGestureDetails 类型
type DragGestureDetails = {
time: number
location: Point
startLocation: Point
translation: Size
velocity: Size
predictedEndLocation: Point
predictedEndTranslation: Size
}
示例
<VStack
onDragGesture={{
minDistance: 5,
coordinateSpace: 'global',
onChanged: details => {
console.log('当前坐标:', details.location)
console.log('偏移量:', details.translation)
},
onEnded: details => {
console.log('预测结束位置:', details.predictedEndLocation)
}
}}
/>
二、Gesture 类接口(高级用法)
若需要更复杂的组合或同时识别多个手势,可使用 Gesture 类与 gesture 修饰符。
所有手势均返回一个 GestureInfo 实例,通过 .onChanged() 与 .onEnded() 注册事件。
1. GestureInfo 类
class GestureInfo<Options, Value> {
type: string
options: Options
onChanged(callback: (value: Value) => void): this
onEnded(callback: (value: Value) => void): this
}
示例
<Text
gesture={
TapGesture()
.onEnded(() => console.log('点击结束'))
}
/>
2. TapGesture(点击手势)
declare function TapGesture(count?: number): GestureInfo<number | undefined, void>
示例
<Text
gesture={
TapGesture(2)
.onEnded(() => console.log('双击了'))
}
/>
3. LongPressGesture(长按手势)
declare function LongPressGesture(options?: LongPressGestureOptions): GestureInfo<LongPressGestureOptions, boolean>
type LongPressGestureOptions = {
minDuration?: number
maxDuration?: number
}
示例
<Text
gesture={
LongPressGesture({ minDuration: 800 })
.onChanged(() => console.log('正在长按'))
.onEnded(() => console.log('长按完成'))
}
/>
4. DragGesture(拖动手势)
declare function DragGesture(options?: DragGestureOptions): GestureInfo<DragGestureOptions, DragGestureDetails>
type DragGestureOptions = {
minDistance?: number
coordinateSpace?: 'local' | 'global'
}
示例
<VStack
gesture={
DragGesture({ coordinateSpace: 'global' })
.onChanged(d => console.log('偏移', d.translation))
.onEnded(d => console.log('速度', d.velocity))
}
/>
5. MagnifyGesture(缩放手势)
declare function MagnifyGesture(minScaleDelta?: number | null): GestureInfo<number | null | undefined, MagnifyGestureValue>
type MagnifyGestureValue = {
time: Date
magnification: number
startAnchor: Point
startLocation: Point
velocity: number
}
示例
<Text
gesture={
MagnifyGesture(0.05)
.onChanged(v => console.log('缩放倍率', v.magnification))
.onEnded(() => console.log('缩放结束'))
}
/>
6. RotateGesture(旋转手势)
declare function RotateGesture(minAngleDelta?: Angle | null): GestureInfo<Angle | null | undefined, RotateGestureValue>
type RotateGestureValue = {
rotation: AngleValue
velocity: AngleValue
startAnchor: Point
time: Date
}
type AngleValue = {
radians: number
degrees: number
magnitude: number
animatableData: number
}
示例
<ZStack
gesture={
RotateGesture()
.onChanged(v => console.log('旋转角度', v.rotation.degrees))
.onEnded(() => console.log('旋转完成'))
}
/>
三、手势修饰符(Gesture Modifiers)
以下属性可添加在任何视图上,用于控制手势识别行为。
type GesturesProps = {
gesture?: GestureProps
simultaneousGesture?: GestureProps
highPriorityGesture?: GestureProps
defersSystemGestures?: EdgeSet
}
1. gesture
为视图添加一个手势。
<Text
gesture={
TapGesture()
.onEnded(() => console.log('点击'))
}
/>
2. highPriorityGesture
使该手势的识别优先于同视图上的其他手势。
<Text
highPriorityGesture={
TapGesture(2)
.onEnded(() => console.log('双击优先'))
}
/>
3. simultaneousGesture
允许多个手势同时识别。
<Text
simultaneousGesture={
LongPressGesture()
.onEnded(() => console.log('长按'))
}
gesture={
TapGesture()
.onEnded(() => console.log('点击'))
}
/>
设置屏幕边缘的优先权,使自定义手势优先于系统手势(如返回手势)。
<VStack defersSystemGestures="all">
<Text>边缘手势优先</Text>
</VStack>
四、GestureMask(手势优先级控制)
定义当添加多个手势时的优先策略。
type GestureMask = "all" | "gesture" | "subviews" | "none"
示例
<VStack
gesture={{
gesture: TapGesture().onEnded(() => console.log('Tapped')),
mask: 'gesture'
}}
>
<Text>Tap me</Text>
</VStack>
五、总结对比表
输入来源过滤(iOS 27.0+)
GestureInputKinds 可以是 "all",或由 "directTouch"、"indirectTouch"、"pencil"、"pointer" 组成的数组。省略表示允许全部来源,空数组表示不接受任何来源。旧系统忽略过滤参数,保留原有手势行为。
onTapGesture、onLongPressGesture、onDragGesture 的对象参数支持 inputKinds。onTapGesture.perform 的对象形式会收到指定坐标空间的 { x, y },函数简写仍不带参数;count 默认 1。
TapGesture 支持原有数字 count 或 { count?, inputKinds? };DragGesture 与 LongPressGesture 在原有 options 中增加 inputKinds;RotateGesture(minAngleDelta?, inputKinds?) 和 MagnifyGesture(minScaleDelta?, inputKinds?) 增加可选第二参数,保留旧调用方式。通过 gesture、simultaneousGesture、highPriorityGesture 使用手势对象时同样生效。
<Text onTapGesture={{ inputKinds: ["pointer"], perform: point => console.log(point) }}>Tap</Text>
<Text gesture={TapGesture({ count: 2, inputKinds: ["directTouch"] }).onEnded(() => {})}>Double tap</Text>
<Text gesture={MagnifyGesture(0.01, ["directTouch"])}>Zoom</Text>
输入来源类型
type GestureInputKind = "directTouch" | "indirectTouch" | "pencil" | "pointer"
type GestureInputKinds = "all" | GestureInputKind[]